package com.micro.frog.rbac.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.micro.frog.common.base.PageRes;
import com.micro.frog.common.base.Result;
import com.micro.frog.common.utils.BeanCopyUtil;
import com.micro.frog.rbac.dto.MenuDTO;
import com.micro.frog.rbac.entity.MenuDO;
import com.micro.frog.rbac.entity.RoleMenuDO;
import com.micro.frog.rbac.entity.UserRoleDO;
import com.micro.frog.rbac.enums.UserTypeEnum;
import com.micro.frog.rbac.mapper.MenuMapper;
import com.micro.frog.rbac.service.MenuService;
import com.micro.frog.rbac.service.RoleMenuService;
import com.micro.frog.rbac.service.UserRoleService;
import com.micro.frog.rbac.vo.MenuTreeVO;
import com.micro.frog.rbac.vo.MenuVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * @author :  ljh
 * @date : 2018/4/2
 **/
@Service
@AllArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuDO> implements MenuService {

    private final UserRoleService userRoleService;
    private final RoleMenuService roleMenuService;

    @Override
    public List<MenuVO> userMenus(Long userId, Integer userType) {
        List<MenuVO> menuVOS = new ArrayList<>();
        UserRoleDO userRole = new UserRoleDO();
        userRole.setUserId(userId);
        List<UserRoleDO> list = userRoleService.queryList(userRole);
        if (!CollectionUtils.isEmpty(list)) {
            List<Long> roleIds = new ArrayList<>();
            list.forEach(a -> roleIds.add(a.getRoleId()));
            List<RoleMenuDO> roleMenus = roleMenuService.queryByRoleIds(roleIds);
            List<Long> menuIds = new ArrayList<>();
            if (!CollectionUtils.isEmpty(roleMenus)) {
                roleMenus.forEach(a -> menuIds.add(a.getMenuId()));
            }
            List<MenuDO> menus = this.getByIds(menuIds);
            menuVOS = buildMenuVo(menus);
        } else {
            //超级管理员强制拥有所有菜单
            if (UserTypeEnum.SUPER_ADMIN.getCode().equals(userType)) {
                return buildMenuVo(this.list());
            }
        }
        return menuVOS;
    }

    private List<MenuDO> getByIds(List<Long> menuIds) {
        QueryWrapper<MenuDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("menu_id", menuIds);
        queryWrapper.eq("is_deleted", "N");
        return this.list(queryWrapper);
    }

    @Override
    public List<MenuVO> queryList(MenuDO query) {
        QueryWrapper<MenuDO> wrapper = new QueryWrapper<>();
        if (query != null) {
            wrapper.setEntity(query);
        }
        List<MenuDO> list = this.list(wrapper);
        List<MenuVO> vos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            for (MenuDO menuDo : list) {
                MenuVO menuVo = new MenuVO();
                BeanCopyUtil.copy(menuDo, menuVo);
                vos.add(menuVo);
            }
        }
        return vos;
    }

    @Override
    public Result<PageRes<MenuDO>> queryPage(MenuDTO queryVo) {
        MenuDO menuDo = new MenuDO();
        BeanCopyUtil.copy(queryVo, menuDo);
        QueryWrapper<MenuDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(menuDo);
        IPage<MenuDO> iPage = this.page(new Page<>(queryVo.getPageNum(), queryVo.getPageSize()));
        return Result.success(PageRes.success(iPage.getCurrent(), iPage.getSize(), iPage.getTotal(), iPage.getRecords()));
    }

    @Override
    public boolean add(MenuVO menuVo) {
        MenuDO menuDo = new MenuDO();
        BeanCopyUtil.copy(menuVo, menuDo);
        return this.save(menuDo);
    }

    @Override
    public boolean delete(Long menuId) {
        MenuDO menuDo = new MenuDO();
        menuDo.setId(menuId);
        menuDo.setIsDeleted("Y");
        return this.updateById(menuDo);
    }

    @Override
    public boolean update(MenuVO menuVo) {
        MenuDO menuDo = new MenuDO();
        BeanCopyUtil.copy(menuVo, menuDo);
        return this.updateById(menuDo);
    }

    @Override
    public List<MenuTreeVO> tree() {
        List<MenuTreeVO> vos = new ArrayList<>();
        List<MenuDO> data = this.list();
        if (!CollectionUtils.isEmpty(data)) {
            vos = buildTreeVO(data);
        }
        return vos;
    }

    private List<MenuTreeVO> buildTreeVO(List<MenuDO> box) {
        List<MenuTreeVO> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(box)) {
            for (int i = 0; i < box.size(); i++) {
                MenuDO menu = box.get(i);
                if (menu != null && menu.getPid() == 0) {
                    list.add(buildMenuTreeVO(menu, box));
                }
            }
        }
        return list;
    }

    private List<MenuTreeVO> buildSubTree(List<MenuDO> box, Long pid) {
        List<MenuTreeVO> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(box)) {
            for (int i = 0; i < box.size(); i++) {
                MenuDO menu = box.get(i);
                if (menu != null && pid.equals(menu.getPid())) {
                    list.add(buildMenuTreeVO(menu, box));
                }
            }
        }
        return list;
    }

    private MenuTreeVO buildMenuTreeVO(MenuDO menu, List<MenuDO> box) {
        MenuTreeVO treeVO = new MenuTreeVO();
        treeVO.setTitle(menu.getName());
        treeVO.setValue(menu.getId());
        treeVO.setData(buildSubTree(box, menu.getId()));
        return treeVO;
    }

    private List<MenuVO> buildMenuVo(List<MenuDO> menus) {
        List<MenuVO> vos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(menus)) {
            for (MenuDO menuDo : menus) {
                boolean isSupperLevel = null == menuDo.getLevel() || 0 == menuDo.getLevel();
                boolean isSupperId = null == menuDo.getPid() || 0 == menuDo.getPid();
                if (isSupperLevel && isSupperId) {
                    MenuVO menuVo = new MenuVO();
                    BeanCopyUtil.copy(menuDo, menuVo);
                    menuVo.setChildren(buildChildren(menus, menuVo.getId()));
                    vos.add(menuVo);
                }
            }
        }
        vos.sort(Comparator.comparing(MenuVO::getSort));
        return vos;
    }

    private List<MenuVO> buildChildren(List<MenuDO> menus, Long pid) {
        List<MenuVO> vos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(menus)) {
            for (MenuDO menuDo : menus) {
                if (null != pid && pid.equals(menuDo.getPid())) {
                    MenuVO menuVo = new MenuVO();
                    BeanCopyUtil.copy(menuDo, menuVo);
                    vos.add(menuVo);
                }
            }
        }
        vos.sort(Comparator.comparing(MenuVO::getSort));
        return vos;
    }
}
